/**************************************************************************
* Copyright (c) 2010 - Wii Banner Player Project
* Copyright (c) 2012 - Dimok
* Copyright (c) 2012 - giantpune
* 
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
* 
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
* 
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
* 
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 
* 3. This notice may not be removed or altered from any source
* distribution.
* 
* Modified by dj_skual
* for SaveGame Manager GX 2012
* 
**************************************************************************/
#include "Texture.h"
#include "../stdafx.h"

Texture::~Texture()
{
	if(texture_data)
		free(texture_data);
}

void Texture::Load(const u8 *file )
{
	if(!file)
		return;

	header = (Texture::Header *) file;
	
	if (header->magic != MAGIC) //! bad header
	{
		header = NULL;
		return;
	}

	u32 texture_count = header->num_textures;
	//! only support a single texture
	if (texture_count > 1) texture_count = 1;

	//! read textures
	const TPL_Texture *tpl_list = (const TPL_Texture *) (file + header->header_size);

	for(u32 i = 0; i < texture_count; i++)
	{
		//! seek to texture header
		const TPL_Texture_Header *texture = (const TPL_Texture_Header *) (file + tpl_list[i].texture_offset);
		
		u8 mipmap = 0;
		u8 bias_clamp = 0;
		
		if(texture->max_lod > 0)
			mipmap = GX_TRUE;
		if(texture->lod_bias > 0.0f)
			bias_clamp = GX_ENABLE;
		
		//! texture data
		u8 *texture_data = (u8 *) (file + texture->offset);
		int tex_size = GX_GetTexBufferSize(texture->width, texture->height, texture->format, mipmap, texture->max_lod);
		DCFlushRange(texture_data, tex_size);
		
		//! seek to/read palette header
		if (tpl_list[i].palette_offset != 0)
		{
			palette = (TPL_Palette_Header *) (file + tpl_list[i].palette_offset);
			
			//! load the texture
			GX_InitTexObjCI(&texobj, texture_data, texture->width, texture->height, texture->format,
							   texture->wrap_s, texture->wrap_t, mipmap, 0);
		}
		else
		{
			//! load the texture
			GX_InitTexObj(&texobj, texture_data, texture->width, texture->height, texture->format,
								   texture->wrap_s, texture->wrap_t, mipmap);
		}
		
		//! filter mode
		if(mipmap)
		{
			GX_InitTexObjLOD(&texobj, texture->min, texture->mag, texture->min_lod, texture->max_lod,
							 		  texture->lod_bias, bias_clamp, bias_clamp, texture->edge_lod);
		}
	}
}

void Texture::Apply(u8 &tlutName, u8 map_id, u8 wrap_s, u8 wrap_t) const
{
	if(!header)
		return;
	
	if(tlutName >= 20 || map_id >= 8)
		return;
	
	//! create a temporary texture object to not modify the original with the wrap_s and wrap_t parameters
	GXTexObj tmpTexObj;
	for(int i = 0; i < 8; ++i)
		tmpTexObj.val[i] = texobj.val[i];
	
	//! assume that if there is a palette header, then this format is a CIx one
	if(palette)
	{
		//! seek to/read palette data
		u8 *tlut_data = (u8 *) (((u8 *) header) + palette->offset);
		
		//! load tlut
		GXTlutObj tlutobj;
		GX_InitTlutObj(&tlutobj, tlut_data, palette->format, palette->num_items );
		GX_LoadTlut(&tlutobj, tlutName);
		GX_InitTexObjTlut((GXTexObj *) &tmpTexObj, tlutName);
		tlutName++;
	}

	GX_InitTexObjWrapMode((GXTexObj *) &tmpTexObj, wrap_s, wrap_t);
	GX_LoadTexObj((GXTexObj *) &tmpTexObj, map_id);
}

void Texture::Render(f32 xpos, f32 ypos, f32 zpos, f32 width, f32 height, f32 degrees, f32 scaleX, f32 scaleY, u8 alpha)
{
	u8 Tlut = 0;
	Apply(Tlut, GX_TEXMAP0, GX_CLAMP, GX_CLAMP);

	GX_ClearVtxDesc();
	GX_InvVtxCache();
	GX_InvalidateTexAll();
	
	GX_SetVtxDesc(GX_VA_POS, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_CLR0, GX_DIRECT);
	GX_SetVtxDesc(GX_VA_TEX0, GX_DIRECT);

	Mtx m, m1, m2, mv;
	f32 halfwidth = width * 0.5f;
	f32 halfheight = height * 0.5f;
	guMtxIdentity(m1);
	guMtxScaleApply(m1, m1, scaleX, scaleY, 1.0f);
	guMtxRotDeg(m2, 'z', degrees);
	guMtxConcat(m2, m1, m);

	guMtxTransApply(m, m, xpos+halfwidth, ypos+halfheight, zpos);
	guMtxConcat(GXmodelView2D, m, mv);
	GX_LoadPosMtxImm(mv, GX_PNMTX0);

	GX_Begin(GX_QUADS, GX_VTXFMT0, 4);
	GX_Position3f32(-halfwidth, -halfheight, 0.0f);
	GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
	GX_TexCoord2f32(0.0f, 0.0f);

	GX_Position3f32(halfwidth, -halfheight, 0.0f);
	GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
	GX_TexCoord2f32(1.0f, 0.0f);

	GX_Position3f32(halfwidth, halfheight, 0.0f);
	GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
	GX_TexCoord2f32(1.0f, 1.0f);

	GX_Position3f32(-halfwidth, halfheight, 0.0f);
	GX_Color4u8(0xFF, 0xFF, 0xFF, alpha);
	GX_TexCoord2f32(0.0f, 1.0f);
	
	GX_End();

	GX_LoadPosMtxImm(GXmodelView2D, GX_PNMTX0);
}
